home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / apps / other / typist.arc / TYPIST.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-19  |  9.8 KB  |  448 lines

  1. /* This program will print out exercise lines to the display, and
  2.    then check for correct typing.
  3. */
  4.  
  5. /* Ported to the Atari-ST by Randy Hosler on May 16, 1992.
  6.    Ported from unix sources, original author unknown.
  7.    Compiled with HSC 1.33 and MiNT libs.
  8.    cc typist.c libm1.a libm.a
  9.    Looks for *.typ files in d:\sozobon\lib\typist\ or current dir.
  10.                      ( see find_lesson() )
  11. */
  12.  
  13. #include <stdio.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include <memory.h>
  17. #include <ctype.h>
  18. #include <time.h>
  19. #include <osbind.h>
  20.  
  21. typedef unsigned char BoolType;
  22. #if !defined(FALSE)
  23. #define FALSE 0
  24. #define TRUE 1
  25. #endif
  26.  
  27. #if !defined(NULL)
  28. #define NULL 0
  29. #endif
  30.  
  31. #define CLRSCREEN  Cconws("\033H\033J")
  32. #define BEEP  Cconout('\007')
  33.  
  34. #define ASCII_ESC 27
  35. #define ASCII_BS  8
  36. #define ASCII_RUBOUT 127
  37.  
  38. #define STR_SIZE 256
  39. typedef char StrType[STR_SIZE + 1];
  40.  
  41. #define MAX_LINES 1500
  42. char *cached_lines[MAX_LINES];
  43.  
  44. int linesInLesson;
  45. int exerciseStart;
  46. int newStart;
  47.  
  48. FILE *lesson_file;
  49. StrType current_line;
  50.  
  51. mvcur(r,c)
  52. int r,c;
  53. {
  54.     Cconout('\033');
  55.     Cconout('Y');
  56.     Cconout(r+040);
  57.     Cconout(c+040);
  58. }
  59.  
  60. wait_user() /* Get any response from user before proceeding */
  61. {
  62. mvcur(23, 0);
  63. Cconws("Press any key to continue...");
  64. Cnecin();
  65. }
  66.  
  67. void get_end_line() /* Read end of line, should be smarter... */
  68. {
  69. Cnecin();
  70. }
  71.  
  72. int cleanup() /* cleanup routine, esp. SIGINT */
  73. {
  74. Cconws("\r\n");
  75. exit(0);
  76. }
  77.  
  78. char *git_lesson() /* Ask user for desired lesson */
  79. {
  80. static StrType response;
  81.  
  82. mvcur(0,0);
  83. Cconws("  Several lessons are available:\r\n");
  84. Cconws("        Quick QWERTY course (q1 - q5)\r\n");
  85. Cconws("        Long QWERTY course  (r1 - r14)\r\n");
  86. Cconws("        QWERTY touch typing (t1 - t16)\r\n");
  87. Cconws("        Yet Another QWERTY  (v1 - v20)\r\n");
  88. Cconws("        QWERTY Review       (u1 - u13)\r\n");
  89. Cconws("        Dvorak touch typing (d1 - d14)\r\n");
  90. Cconws("        Typing drills       (m1 - m11)\r\n");
  91. Cconws("        Speed drills        (s1 - s4)\r\n");
  92. Cconws("        Calculator keypad   (n1 - n3)\r\n");
  93. mvcur(11,0);
  94. Cconws(" Press return to exit or else type the desired lesson name: ");
  95. gets(response);
  96. if (strlen(response) == 0)
  97.   cleanup();
  98. return response;
  99. }
  100.  
  101. BoolType get_lesson_line() /* Read line of input from user, in canonical mode */
  102. {
  103. if (feof(lesson_file))
  104.   return FALSE;
  105. if (fgets(current_line, STR_SIZE, lesson_file) == NULL)
  106.   current_line[0] = '\0';
  107. else {
  108.   if (current_line[strlen(current_line) - 1] == '\n')
  109.     current_line[strlen(current_line) - 1] = '\0';
  110.   }
  111. return TRUE;
  112. }
  113.  
  114. BoolType find_lesson(name) /*locate lesson leave file open so next line begins*/
  115. char *name;
  116. {
  117. StrType fullName;
  118. StrType target;
  119. StrType response;
  120. BoolType done = FALSE;
  121.  
  122. sprintf(fullName, "d:\\sozobon\\lib\\typist\\%c.typ", name[0]);
  123. sprintf(target, "*%c%s*", toupper(name[0]), &name[1]);
  124. lesson_file = fopen(fullName, "r");
  125. if (lesson_file == NULL) {
  126.   sprintf(fullName, "%c.typ", name[0]);  /* try current dir */
  127.   lesson_file = fopen(fullName, "r");
  128.   if (lesson_file == NULL) {
  129.     sprintf(response, "Can't open file %s\n", fullName);
  130.     Cconws("\r\n");
  131.     Cconws(response);
  132.     wait_user();
  133.     return FALSE;
  134.     }
  135.   }
  136. while (!done) {
  137.   if (!get_lesson_line())
  138.     break;
  139.   if (strncmp(current_line, target, 5) == 0)
  140.     done = TRUE;
  141.   }
  142. if (!done) {
  143.   sprintf(response, "Lesson %s is not available.\n", &name[1]);
  144.   Cconws("\r\n");
  145.   Cconws(response);
  146.   wait_user();
  147.   return FALSE;
  148.   }
  149. linesInLesson = 0;
  150. done = FALSE;
  151. while (!done) {
  152.   if (!get_lesson_line()) {
  153.     done = TRUE;
  154.     break;
  155.     }
  156.   if (current_line[0] == '*') {
  157.     done = TRUE;
  158.     break;
  159.     }
  160.   if (linesInLesson == MAX_LINES) {
  161.     }
  162.   if (cached_lines[linesInLesson] != NULL) {
  163.     free(cached_lines[linesInLesson]);
  164.     cached_lines[linesInLesson] = NULL;
  165.     }
  166.   cached_lines[linesInLesson] = (char *)malloc(strlen(current_line) + 1);
  167.   if (cached_lines[linesInLesson] == NULL) {
  168.     fprintf(stderr, "malloc() failure\n");
  169.     exit(1);
  170.     }
  171.   strcpy(cached_lines[linesInLesson], current_line);
  172.   linesInLesson ++;
  173.   }
  174. return TRUE;
  175. }
  176.  
  177. void get_exercise(startLine, kind, newStart) /*get length and kind of exercise*/
  178. int startLine;
  179. char *kind;
  180. int *newStart;
  181. {
  182. char *thisLine;
  183. int lineLength;
  184.  
  185. *newStart = startLine;
  186. *kind = 'I'; /* default... */
  187. /* Determine end of exercise */
  188. while (TRUE) {
  189.   if (*newStart >= linesInLesson)
  190.     break; /* done */
  191.  
  192.   thisLine = cached_lines[*newStart];
  193.   lineLength = strlen(thisLine);
  194.   if (thisLine[lineLength - 2] == '\\') { /* expected terminator */
  195.     *kind = thisLine[lineLength - 1];
  196.     thisLine[lineLength - 2] = '\0'; /* remove */
  197.     (*newStart) ++;
  198.     break;
  199.     }
  200.   if (thisLine[lineLength - 1] == '\\') /* compatibility with BASIC */
  201.     thisLine[lineLength - 1] = '\0'; /* also remove */
  202.   (*newStart) ++;
  203.   }
  204. }
  205.  
  206. void displaySpeed(totalChars, elapsed, errs) /* show how fast you were */
  207. int totalChars;
  208. long elapsed;
  209. int errs;
  210. {
  211.   elapsed = elapsed / 200;
  212.   {
  213.   double testTime = (double)elapsed / (double)60.0; /* time in minutes */
  214.   double words = (double)totalChars / 5.0;
  215.   double speed = words / testTime;
  216.   double adjustedSpeed;
  217.   StrType message;
  218.  
  219.   words -= errs;
  220.   adjustedSpeed = words / testTime;
  221.  
  222.   mvcur(19, 19);
  223.   sprintf(message, "raw speed      = %f wpm", speed);
  224.   Cconws(message);
  225.   mvcur(20, 19);
  226.   sprintf(message, "adjusted speed = %f wpm", adjustedSpeed);
  227.   Cconws(message);
  228.   mvcur(21, 19);
  229.   sprintf(message, "            with %f%s errors",
  230.     (double)100.0 * errs / totalChars, "%");
  231.   Cconws(message);
  232.   wait_user();
  233.   }
  234. }
  235.  
  236. void do_drill() /* \D, a drill */
  237. {
  238. int tries;
  239. int errors;
  240. int totalChars;
  241. int i, j;
  242. char *thisLine;
  243. int thisLength;
  244. char ch;
  245. long startTime, endTime;
  246.  
  247. tries = 0;
  248. do { /* a try */
  249.   totalChars = 0;
  250.   errors = 0;
  251.   tries ++;
  252.  
  253.   /* display drill pattern */
  254.   for (i = exerciseStart; i < newStart; i ++) {
  255.     mvcur(3 + (i - exerciseStart) * 2, 0);
  256.     Cconws(cached_lines[i]);
  257.     totalChars += strlen(cached_lines[i]) + 1; /* +1 for NULL */
  258.     }
  259.  
  260.   /* run the drill */
  261.   for (i = exerciseStart; i < newStart; i ++) {
  262.     thisLine = cached_lines[i];
  263.     thisLength = strlen(thisLine);
  264.  
  265.     mvcur(4 + (i - exerciseStart) * 2, 0);
  266.     for (j = 0; j < thisLength; j ++) {
  267.       ch = Cnecin();
  268.       if (i == exerciseStart && j == 0)
  269.         startTime = clock(); /* timer doesn't run till first stroke */
  270.       if (ch == ASCII_ESC) {
  271.         CLRSCREEN;
  272.         goto ALL_DONE;
  273.         }
  274.       if (ch != thisLine[j]) {
  275.         Cconout('X');
  276.         BEEP;
  277.         errors ++;
  278.         }
  279.       else
  280.         Cconout(ch);
  281.       }
  282.     get_end_line();
  283.     }
  284.   endTime = clock();
  285.  
  286.   displaySpeed(totalChars, endTime - startTime, errors);
  287.   CLRSCREEN;
  288.   if (errors > 0 && tries < 3) {
  289.     mvcur(0, 0);
  290.     Cconws("Try again...");
  291.     }
  292.   tries ++;
  293.   } while (errors > 0 && tries < 4);
  294. ALL_DONE:;
  295. }
  296.  
  297. void do_para()
  298. /* P, practice paragraph */
  299. {
  300. int i, j;
  301. char *thisLine;
  302. int thisLength;
  303. char ch;
  304. int totalChars = 0;
  305. int errors = 0;
  306. long startTime, endTime;
  307.  
  308. /* print out practice text */
  309. for (i = exerciseStart; i < newStart; i ++) {
  310.   mvcur(3 + (i - exerciseStart), 0);
  311.   Cconws(cached_lines[i]);
  312.   totalChars += strlen(cached_lines[i]);
  313.   }
  314.  
  315. mvcur(3, 0);
  316. for (i = exerciseStart; i < newStart; i ++) {
  317.   mvcur(3 + (i - exerciseStart), 0);
  318.   thisLine = cached_lines[i];
  319.   thisLength = strlen(thisLine);
  320.   for (j = 0; j < thisLength; j ++) {
  321.     ch = Cnecin();
  322.     if (i == exerciseStart && j == 0)
  323.       startTime = clock(); /* timer doesn't run till first stroke */
  324.     if (ch == ASCII_ESC) {
  325.       CLRSCREEN;
  326.       goto ALL_DONE;
  327.       }
  328.     /* Allow backspace */
  329.     if (j != 0 && (ch == ASCII_BS || ch == ASCII_RUBOUT)) {
  330.       j --;
  331.       mvcur(3 + (i - exerciseStart), j);
  332.       Cconout(thisLine[j]);
  333.       mvcur(3 + (i - exerciseStart), j);
  334.       j --;
  335.       continue; /* but notice that errors accumulate */
  336.       }
  337.     if (ch != thisLine[j]) {
  338.       mvcur(3 + (i - exerciseStart), j);
  339.       Cconout(thisLine[j]);
  340.       errors ++;
  341.       }
  342.     else
  343.       mvcur(3 + (i - exerciseStart), j + 1);
  344.     }
  345.     get_end_line();
  346.   }
  347.   endTime = clock();
  348.  
  349.   displaySpeed(totalChars, endTime - startTime, errors);
  350. ALL_DONE:;
  351. }
  352.  
  353. void do_type()
  354. /* T, type out a lesson */
  355. {
  356. int i;
  357.  
  358. CLRSCREEN;
  359. for (i = exerciseStart; i < newStart; i ++) {
  360.   mvcur(1 + (i - exerciseStart), 0);
  361.   Cconws(cached_lines[i]);
  362.   }
  363. wait_user();
  364. CLRSCREEN;
  365. }
  366.  
  367. void do_instruction() 
  368. /* I, instruction line */
  369. {
  370. CLRSCREEN;
  371. mvcur(0, 0);
  372. Cconws(cached_lines[exerciseStart]);
  373. }
  374.  
  375. void do_clear() 
  376. /* B, clear screen */
  377. {
  378. CLRSCREEN;
  379. mvcur(1, 29);
  380. Cconws(cached_lines[exerciseStart]);
  381. wait_user();
  382. }
  383.  
  384. void give_lesson() 
  385. /* dance through lesson file */
  386. {
  387. char kind;
  388.  
  389. exerciseStart = 0;
  390. while (TRUE) {
  391.   get_exercise(exerciseStart, &kind, &newStart);
  392.   switch (kind) {
  393.     case 'B':
  394.       do_clear();
  395.       break;
  396.  
  397.     case 'P':
  398.       do_para();
  399.       break;
  400.  
  401.     case 'T':
  402.       do_type();
  403.       break;
  404.  
  405.     case 'D':
  406.       do_drill();
  407.       break;
  408.  
  409.     case 'I':
  410.       do_instruction();
  411.       break;
  412.  
  413.     default:
  414.       fprintf(stderr, "Unknown exercise near line %d of this lesson\n",
  415.           newStart - 1);
  416.       exit(1);
  417.       break;
  418.     }
  419.   exerciseStart = newStart;
  420.   if (exerciseStart >= linesInLesson)
  421.     break;
  422.   }
  423. }
  424.  
  425. int main(argc, argv)
  426. int argc;
  427. char *argv[];
  428. {
  429. char *lessonName;
  430. int i;
  431.  
  432. CLRSCREEN;
  433.  
  434. for (i = 0; i < MAX_LINES; i ++)
  435.   cached_lines[i] = NULL;
  436.  
  437. /* Start and format screen.  Open and read exercise file.
  438.    Inquire for lesson to run */
  439. while (TRUE) {
  440.   CLRSCREEN;
  441.   lessonName = git_lesson();
  442.   if (!find_lesson(lessonName))
  443.     continue;
  444.   give_lesson();
  445.   }
  446. }
  447.  
  448.